package com.dau.service.customer.draw.impl;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dau.common.util.GlobalConstants;
import com.dau.common.util.RedisUtils;
import com.dau.entity.customer.LuckyDraw;
import com.dau.entity.system.prize.SysPrize;
import com.dau.mapper.mapper.draw.LuckyDrawMapper;
import com.dau.service.customer.draw.LuckyDrawService;
import com.dau.service.system.prize.PrizeService;
import jakarta.annotation.Resource;
import org.redisson.api.RLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * 抽奖服务
 *
 * @author tzj
 * @date 2024/12/10
 */
@Service
public class LuckyDrawServiceImpl extends ServiceImpl<LuckyDrawMapper, LuckyDraw> implements LuckyDrawService {
    private static final Logger logger = LoggerFactory.getLogger(LuckyDrawServiceImpl.class);
    @Resource
    private PrizeService prizeService;


    /**
     * 幸运抽奖
     *
     * @param activityId 活动id
     * @return {@link LuckyDraw }
     */
    @Override
    public LuckyDraw luckyDraw(Long activityId) {
        logger.info("开始抽奖，活动ID: {}", activityId);
        RLock lock = RedisUtils.getClient().getLock("lucky_draw_lock:" + activityId);
        try {
            if (!tryAcquireLock(lock, activityId)) {
                return null;
            }
            List<SysPrize> prizeList = getPrizeList(activityId);
            if (prizeList.isEmpty()) {
                logger.error("未找到活动ID为 {} 的抽奖活动", activityId);
                throw new IllegalArgumentException("请确认参加的抽奖活动");
            }
            long totalQuantity = calculateTotalQuantity(prizeList);
            if (totalQuantity <= 0) {
                logger.error("活动ID为 {} 的奖品总数量为0", activityId);
                return LuckyDraw.builder().winning(false).prizeName("未中奖").build();
            }
            SysPrize selectedPrize = selectPrize(prizeList, totalQuantity);
            SysPrize guaranteedReward = getGuaranteedReward(prizeList);
            return createLuckyDrawResult(activityId, selectedPrize, guaranteedReward);
        } catch (InterruptedException e) {
            logger.error("抽奖过程中发生中断，活动ID: {}", activityId, e);
            Thread.currentThread().interrupt();
            throw new RuntimeException("抽奖过程中发生中断");
        } finally {
            releaseLockIfHeld(lock);
        }
    }

    /**
     * 尝试获取锁
     *
     * @param lock       锁
     * @param activityId 活动id
     * @return boolean
     * @throws InterruptedException 中断异常
     */
    private boolean tryAcquireLock(RLock lock, Long activityId) throws InterruptedException {
        boolean isLocked = lock.tryLock(10, 10, TimeUnit.SECONDS);
        if (!isLocked) {
            logger.error("获取锁失败，活动ID: {}", activityId);
            throw new RuntimeException("抽奖请求过于频繁，请稍后再试");
        }
        return true;
    }

    /**
     * 获取奖品列表
     *
     * @param activityId 活动id
     * @return {@link List }<{@link SysPrize }>
     */
    private List<SysPrize> getPrizeList(Long activityId) {
        return prizeService.list(new QueryWrapper<SysPrize>().eq("activity_id", activityId));
    }

    /**
     * 计算总数量
     *
     * @param prizeList 奖品列表
     * @return long
     */
    private long calculateTotalQuantity(List<SysPrize> prizeList) {
        return prizeList.stream().mapToLong(SysPrize::getQuantity).sum() * 2;
    }

    /**
     * 中奖奖品
     *
     * @param prizeList     奖品列表
     * @param totalQuantity 总数量
     * @return {@link SysPrize }
     */
    private SysPrize selectPrize(List<SysPrize> prizeList, long totalQuantity) {
        Random random = new Random();
        long randomNumber = random.nextLong(totalQuantity);
        int cumulativeQuantity = 0;
        for (SysPrize prize : prizeList) {
            cumulativeQuantity += prize.getQuantity();
            if (randomNumber < cumulativeQuantity) {
                return prize;
            }
        }
        return null;
    }

    /**
     * 保底奖励
     *
     * @param prizeList 奖品列表
     * @return {@link SysPrize }
     */
    private SysPrize getGuaranteedReward(List<SysPrize> prizeList) {
        return prizeList.stream()
                .filter(prize -> GlobalConstants.ONE_STR.equals(prize.getGuaranteedReward()) && prize.getQuantity() > 0)
                .findFirst()
                .orElse(null);
    }

    /**
     * 创建抽奖结果
     *
     * @param activityId       活动id
     * @param selectedPrize    精选奖
     * @param guaranteedReward 保证奖励
     * @return {@link LuckyDraw }
     */
    private LuckyDraw createLuckyDrawResult(Long activityId, SysPrize selectedPrize, SysPrize guaranteedReward) {
        SysPrize prizeToAward = selectedPrize != null ? selectedPrize : guaranteedReward;
        if (prizeToAward == null) {
            logger.info("未找到合适的奖品，活动ID: {}", activityId);
            return LuckyDraw.builder().winning(false).prizeName("未中奖").build();
        }
        logger.info("发放奖品: {}", JSONUtil.toJsonStr(prizeToAward));
        LuckyDraw luckyDraw = LuckyDraw.builder()
                .activityId(activityId)
                .prizeId(prizeToAward.getId())
                .prizeName(prizeToAward.getName())
                .build();
        prizeToAward.setQuantity(prizeToAward.getQuantity() - 1);
        prizeService.updateById(prizeToAward);
        return luckyDraw;
    }

    /**
     * 释放锁（如有）
     *
     * @param lock 锁
     */
    private void releaseLockIfHeld(RLock lock) {
        if (lock.isHeldByCurrentThread()) {
            lock.unlock();
        }
    }

}
